export const uuid = () => {
  let timeStr = fillLength(new Date().getTime().toString(16), 12, '0');
  let s = [];
  let hexDigits = "0123456789abcdef";
  for (let i = 0; i < 20 - timeStr.length; i++) {
    s[i] = hexDigits.charAt(Math.floor(Math.random() * 0x10));
  }
  return timeStr + s.join("");
};

export const fillLength = (str, len, fillStr) => {
  if (typeof str === 'undefined' || str == null) {
    str = '';
  }
  if (typeof fillStr === 'undefined' || fillStr == null || fillStr === '') {
    fillStr = '0';
  }

  let fillLen = ((len || 0) - str.length)/fillStr.length;
  if (fillLen > 0) {
    for (let i=0; i<fillLen; i++) {
      str = fillStr + str;
    }
  }

  return str;
};

export const groupBy = (array, groupByFn, sortFn) => {
  const groups = {};
  array.forEach(function (item) {
    const group = JSON.stringify(groupByFn(item));
    //这里利用对象的key值唯一性的，创建数组
    groups[group] = groups[group] || [];
    groups[group].push(item);
  });

  let result = [];
  //最后再利用map循环处理分组出来
  Object.keys(groups).map(function(group) {
    if (sortFn) {
      groups[group].sort(sortFn);
    }
    result.push(groups[group]);
  });

  return result;
};

// 深拷贝对象
export const deepClone = (obj, filterFn = undefined) => {
  const _toString = Object.prototype.toString;

  // null, undefined, non-object, function
  if (!obj || typeof obj !== 'object') {
    return obj;
  }

  // DOM Node
  if (obj.nodeType && 'cloneNode' in obj) {
    return obj.cloneNode(true);
  }

  // Date
  if (_toString.call(obj) === '[object Date]') {
    return new Date(obj.getTime());
  }

  // RegExp
  if (_toString.call(obj) === '[object RegExp]') {
    const flags = [];
    if (obj.global) { flags.push('g') }
    if (obj.multiline) { flags.push('m') }
    if (obj.ignoreCase) { flags.push('i') }

    return new RegExp(obj.source, flags.join(''));
  }

  const result = Array.isArray(obj) ? [] : obj.constructor ? new obj.constructor() : {};

  for (const key in obj) {
    if (typeof filterFn === 'undefined' || filterFn(key, obj)) {
      result[key] = deepClone(obj[key], filterFn);
    }
  }

  return result;
};

export const formatNumber = (number, pattern, prmNullValue) => {
  if(number == null || number === "") return prmNullValue || '';
  if(pattern == null || pattern === "") return number;

  number = (number + "").replace(/,/g, "");
  if(isNaN(number)) return number;

  let patternLen = pattern.length;
  let pointIndex = pattern.indexOf(".");
  let groupIndex = pattern.indexOf(",");
  let pointLen = (pointIndex === -1 ? 0 : patternLen - pointIndex - 1);
  let result = parseFloat(number).toFixed(pointLen) + "";
  if(groupIndex !== -1){
    if(pointIndex === -1) pointIndex = patternLen;
    let len = pointIndex - groupIndex - 1;
    let reg = new RegExp("(-?\\d+)(\\d{" + len + "})");
    while(reg.test(result)) {
      result = result.replace(reg, "$1,$2");
    }
  }

  if (pointLen > 0) {
    for (let i=pattern.length; i--; i > pattern.indexOf('.')) {
      if (pattern.charAt(i) === '0'
          || !(result.charAt(result.length - 1) === '0'
              || result.charAt(result.length - 1) === '.')) {
        break;
      }
      result = result.substring(0, result.length - 1);
      if (pattern.charAt(i) === '.') {
        break;
      }
    }
  }
  return result;
};

export const isDeepEqual = (obj1, obj2) => {
  if (obj1 === obj2) {
    return true;
  }

  if (typeof obj1 !== typeof obj2) {
    return false;
  }

  if (Array.isArray(obj1) !== Array.isArray(obj2)) {
    return false;
  }

  if (typeof obj1 === 'object' && obj1 !== null && obj2 !== null) {
    const keys1 = Object.keys(obj1);
    const keys2 = Object.keys(obj2);

    if (keys1.length !== keys2.length) {
      return false;
    }

    for (const key of keys1) {
      if (!Object.prototype.hasOwnProperty.call(obj2, key)) {
        return false;
      }

      if (!isDeepEqual(obj1[key], obj2[key])) {
        return false;
      }
    }

    return true;
  }

  return obj1 === obj2;
};

const getFunArgs = (func) => {
  return func.toString()
    .match(/function\s.*?\(([^)]*)\)/)[1]
    .split(",")
    .map(arg => arg.replace(/\/\*.*\*\//, '').trim())
    .filter(args => args);
};

export default {
  uuid,
  groupBy,
  deepClone,
  formatNumber,
  isDeepEqual,
  getFunArgs
};